package cloudjunit;

import java.util.ArrayList;
import java.util.List;

import Common.TraceWriter;

import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl;
import com.amazonaws.services.simpleworkflow.flow.WorkflowContext;
import com.amazonaws.services.simpleworkflow.flow.core.Promise;
import com.amazonaws.services.simpleworkflow.flow.core.Promises;
import com.amazonaws.services.simpleworkflow.flow.core.TryCatchFinally;
import com.amazonaws.services.simpleworkflow.flow.annotations.Asynchronous;
import cloudjunit.UnitTestActivitiesClient;
import cloudjunit.UnitTestActivitiesClientImpl;

public class UnitTestWorkflowImpl implements UnitTestWorkflow
{
	private UnitTestActivitiesClient activitiesClient;
    
    private WorkflowContext workflowContext;
    private String workflowId;
    
    static final String S3_RESULTS_REMOTE_PATH = "results/";

    public UnitTestWorkflowImpl()
    {
    	super();
    	workflowId = "";
    	activitiesClient = new UnitTestActivitiesClientImpl();
        workflowContext = (new DecisionContextProviderImpl()).getDecisionContext().getWorkflowContext();
    }
    
    @Override
    public void startJarTestsFlow(final String jarFileRemotePath)
    {
    	TraceWriter.trace("startJarTestsFlow ITERATION STARTED");
    	
    	workflowId = workflowContext.getWorkflowExecution().getWorkflowId();
    	TraceWriter.trace("workflow id: " + workflowId);
    	
    	new TryCatchFinally() {

            @Override
            protected void doTry() throws Throwable {
            	
            	//TraceWriter.trace("0. init workflow");
            	
            	Promise<Void> initPromise = initWorkflow();
            	
            	//TraceWriter.trace("1. looking for UT in jar "+jarFileRemotePath);
            	
            	Promise<List<String>> unitTestsList = findUnitTestsInJar(initPromise, jarFileRemotePath);
            
            	//TraceWriter.trace("2. running tests stage");
            	
            	Promise<List<String>> promisedAllTestResults = runTests(unitTestsList, jarFileRemotePath);
            	
            	//TraceWriter.trace("3. waiting for all tests to complete..");
            	
            	Promise<Void> endPromise = createResultsReport(promisedAllTestResults);
            	
            	//TraceWriter.trace("4. workflow done!");
            	
            	traceFinished(endPromise);
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
            	TraceWriter.trace("BAD BAD caught exception");
            	e.printStackTrace();
            	throw e;
            }

            @Override
            protected void doFinally() throws Throwable {
                TraceWriter.trace("finally");
            }

        };
        
        TraceWriter.trace("flow ITERATION FINISHED");
    }
    
    @Asynchronous
    private Promise<Void> initWorkflow()
    {
    	TraceWriter.trace("initWorkflow()");
    	return activitiesClient.initUnitTestWorkFlowData(workflowId);
    }
    
    @Asynchronous
    private Promise<List<String>> findUnitTestsInJar(Promise<Void> initPromise, String jarFileRemotePath)
    {
    	TraceWriter.trace("findUnitTestsInJar()");
    	return activitiesClient.findUnitTestsInJar(workflowId, jarFileRemotePath);
    }
    
    @Asynchronous
    private Promise<List<String>> runTests(Promise<List<String>> promisedListOfUnitTests, String jarFileRemotePath)
    {
    	TraceWriter.trace("runTests STARTED!");
    	
    	List<String> listOfUnitTests = promisedListOfUnitTests.get();
    	
    	TraceWriter.trace("runTests updating table");
    	
    	List<Promise<String>> listOfPromises = new ArrayList<Promise<String>>();
    	
        for (String unitTestName : listOfUnitTests)
        {
        	TraceWriter.trace("runTests: running test class " + unitTestName);

        	Promise<String> resultStr = activitiesClient.runUnitTestAndUploadResults(workflowId, jarFileRemotePath, S3_RESULTS_REMOTE_PATH, unitTestName);
        	listOfPromises.add(resultStr);
        }
        
        TraceWriter.trace("runTests DONE!");
        
        Promise<List<String>> result = Promises.listOfPromisesToPromise(listOfPromises);
        
        return result;
    }
    
    @Asynchronous
    private Promise<Void> createResultsReport(Promise<List<String>> promisedTestResultsList)
    {
    	List<String> list = promisedTestResultsList.get();
    	TraceWriter.trace("Number of test activies that were ran: " + Integer.toString(list.size()) );
    	
    	return activitiesClient.finalizeWorkFlowData(workflowId);
    }
    
    @Asynchronous
    private void traceFinished(Promise<Void> waitEnd)
    {
    	TraceWriter.trace("FINISEHD workflowId: " + workflowId);
    }
}
